#pragma once

#include <vector>
#include "Matrix.h"

namespace HW2{
	struct Point2D;

	struct Coordinates
	{
		std::vector<double> data;
		

		Coordinates(double x = 0, double y = 0, double z = 0, double h = 1);

		Point2D toPoint2D();

		double& X() { return data[0]; }
		double& Y() { return data[1]; }
		double& Z() { return data[2]; }
		double& H() { return data[3]; }

		void normalize();

		double &get(int i)
		{
			return data[i-1];
		}

		Coordinates operator*(Matrix &m);
		Coordinates &operator*=(Matrix &m);

		Coordinates operator-(Coordinates &other)
		{
			normalize();
			other.normalize();
			return Coordinates(X() - other.X(), Y() - other.Y(), Z() - other.Z());
		}
		Coordinates operator+(Coordinates &other)
		{
			normalize();
			other.normalize();
			return Coordinates(X() + other.X(), Y() + other.Y(), Z() + other.Z());
		}

		/*Coordinates& operator=(Coordinates c){
			X() = c.X();
			Y() = c.Y();
			Z() = c.Z();
			return *this;

		}*/


		Coordinates sub(Coordinates& c){
			return Coordinates(X() - c.X(), Y() - c.Y(), Z() - c.Z());


		}

		Coordinates add(Coordinates& c){
			return Coordinates(X() + c.X(), Y() + c.Y(), Z() + c.Z());
		}

		Coordinates mult(double d){
			return Coordinates(X() *d, Y() * d, Z() * d);

		}
		Coordinates multEq(double d){
			X() *= d;
			Y() *= d;
			Z() *= d;	

		}

		void operator*=(double a)
		{
			normalize();
			X() *= a;
			Y() *= a;
			Z() *= a;	
		}
		Coordinates operator/(double a)
		{
			Coordinates c = *this;
			c.H() *= a;
			c.normalize();
			return c;
		}

		double dot(Coordinates& c){
			return (X()*c.X() + Y()*c.Y() + Z()*c.Z());


		}

		Coordinates& operator+=(Coordinates &other)
		{
			normalize();
			other.normalize();
			X() += other.X();
			Y() += other.Y();
			Z() += other.Z();

			return *this;
		}

		double norm()
		{
			normalize();
			return sqrt(X()*X() + Y()*Y() + Z()*Z());
		}

		void makeUnitVec(){
			double n = norm();
			data[0]= data[0]/n;
			data[1]= data[1]/n;
			data[2]= data[2]/n;
			data[3]= 1;

		}

		Coordinates cross(Coordinates &other)
		{
			normalize();
			other.normalize();
			Coordinates result;
			result.X() = Y()*other.Z() - Z()*other.Y();
			result.Y() = X()*other.Z() - Z()*other.X();
			result.Z() = X()*other.Y() - Y()*other.X();
			result.H() = 1;
			return result;
		}

		static Coordinates Interpolate(Coordinates &start, Coordinates &end,double ratio);
	};

	typedef Coordinates Vector; // A point is also a vector
};

